#ifndef VULKAN_OBJECT_H
#define VULKAN_OBJECT_H

namespace Vulkan {
	struct
	{
		GLFWwindow* window = nullptr;
		VkInstance instance = VK_NULL_HANDLE;
		VkDebugReportCallbackEXT debugCallback = VK_NULL_HANDLE;
		VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
		VkSurfaceKHR surface = VK_NULL_HANDLE;
		VkDevice device = VK_NULL_HANDLE;
		uint32_t graphicsQueueIndex = UINT32_MAX;
		VkPhysicalDeviceMemoryProperties memoryPropertes;
		VkQueue graphicsQueue = VK_NULL_HANDLE;
		VkCommandPool commandPool = VK_NULL_HANDLE;
		VkFormat colorFormat;
		VkRenderPass renderPass = VK_NULL_HANDLE;
		VkExtent2D extend;
		
		VkSwapchainKHR swapchain = VK_NULL_HANDLE;
		std::vector<VkImage> swapchainImages;
		std::vector<VkImageView> swapchainViews;
		std::vector<VkFramebuffer> swapchainFrames;
		struct
		{
			VkFormat format;
			VkImage image = VK_NULL_HANDLE;
			VkDeviceMemory memory = VK_NULL_HANDLE;
			VkImageView view = VK_NULL_HANDLE;
		}depth;
	}context;

	struct Vertex
	{
		glm::vec3 position;
		glm::vec3 normal;
		glm::vec2 uv;

		static std::vector<VkVertexInputBindingDescription> bindings() {
			return { {0, (uint32_t)sizeof(Vertex),VK_VERTEX_INPUT_RATE_VERTEX} };
		}

		static std::vector<VkVertexInputAttributeDescription> attributes() {
			return {	{ 0,0,VK_FORMAT_R32G32B32_SFLOAT,offsetof(Vertex,position) },
						{ 1,0,VK_FORMAT_R32G32B32_SFLOAT,offsetof(Vertex,normal) },
						{ 2,0,VK_FORMAT_R32G32_SFLOAT,offsetof(Vertex,uv) }
			};
		}
	};

	struct Texture
	{
		VkImage image = VK_NULL_HANDLE;
		VkDeviceMemory memory = VK_NULL_HANDLE;
		VkDescriptorImageInfo descriptor;
	};

	struct Box3 {
		glm::vec3 min = glm::vec3(0.0f);
		glm::vec3 max = glm::vec3(0.0f);

		void add(const glm::vec3& p) {
			if (p.x < min.x)min.x = p.x;
			if (p.x > max.x)max.x = p.x;
			if (p.y < min.y)min.y = p.y;
			if (p.y > max.y)max.y = p.y;
			if (p.z < min.z)min.z = p.z;
			if (p.z > max.z)max.z = p.z;
		}

		void add(const Box3& box) {
			if (box.min.x < min.x)min.x = box.min.x;
			if (box.min.y < min.y)min.y = box.min.y;
			if (box.min.z < min.z)min.z = box.min.z;
			if (box.max.x > max.x)max.x = box.max.x;
			if (box.max.y > max.y)max.y = box.max.y;
			if (box.max.z > max.z)max.z = box.max.z;
		}
	};

	struct Mesh{
		uint32_t indexCount = 0;
		uint32_t indexOffset = 0;
		Texture diffus;
		Box3 boundingBox;
		glm::mat4 transform;
		VkPipeline pipeline = VK_NULL_HANDLE;
		VkPipelineLayout layout = VK_NULL_HANDLE;
		VkDescriptorSet set = VK_NULL_HANDLE;
	};

	struct Model
	{
		struct
		{
			VkBuffer buffer = VK_NULL_HANDLE;
			VkDeviceMemory memory = VK_NULL_HANDLE;
		}vertex,index;
		std::vector<Mesh> meshes;
		uint32_t indexCount = 0;
		Box3 boundingBox;
	};
}

#endif // !VULKAN_OBJECT_H